package org.fioma.tree.suffixTree.ukkonen;

import org.fioma.tree.Label;
import org.fioma.tree.suffixTree.SuffixRoot;
import org.fioma.tree.suffixTree.SuffixTree;

public class UkkonenSuffixTree<L extends Label<L>, I extends UkkonenSuffixInternalNode<L, I, F, N>, F extends UkkonenSuffixLeafNode<L, I, F, N>, N extends UkkonenSuffixNode<L, I, F, N>>
		implements SuffixTree<L, I, F, N> {

	int k;
	UkkonenSuffixRoot<L, I, F, N> root;

	public UkkonenSuffixTree(int k, UkkonenSuffixRoot<L, I, F, N> root) {
		this.k = k;
		this.root = root;
	}

	public void addSuffixes(L word) {
		F lastLeaf = root.addWord(word);

		for (int j = 1; lastLeaf != null; j++) {
//			System.out.print(j + " ");
			// find w[j..i-1]
			I parentLastLeaf = lastLeaf.getParent();
			L lastLeafLabel = lastLeaf.getLabel();
			if (parentLastLeaf.isRoot()) {
				lastLeaf = parentLastLeaf.addWord(lastLeafLabel.substring(1));
			} else {
				I suffixLink = parentLastLeaf.getSuffixLink();
				if (suffixLink != null) {
					lastLeaf = suffixLink.addWord(lastLeafLabel);
				} else {
					L parentLastLeafLabel = parentLastLeaf.getLabel();
					I v = parentLastLeaf.getParent();
					I sv;
					if (v.isRoot()) {
						parentLastLeafLabel = parentLastLeafLabel.substring(1);
						sv = v;
						// lastLeaf =
						// v.addWord(parentLastLeafLabel.join(lastLeafLabel));
						// suffixLink = (I)
						// v.findExistentNode(parentLastLeafLabel);
					} else {
						sv = v.getSuffixLink();
						// lastLeaf =
						// sv.addWord(parentLastLeafLabel.join(lastLeafLabel));
						// suffixLink = (I)
						// sv.findExistentNode(parentLastLeafLabel);
					}
					suffixLink = (I) sv.getOrCreateInternalNode(parentLastLeafLabel);
					lastLeaf = suffixLink.addWord(lastLeafLabel);
					parentLastLeaf.setSuffixLink(suffixLink);
				}
			}
		}
	}

	@Override
	public SuffixRoot<L, I, F, N> getRoot() {
		return root;
	}

}
